package chatserver.logging;


import chatserver.netio.Connection;
import java.io.PrintStream;
import java.text.MessageFormat;
import java.util.logging.*;

public class ServerLog {

    private static final Logger logger = Logger.getLogger("ChatServerLog");
    private static boolean didInit = false;

    private static void Init() {
        logger.setUseParentHandlers(false);

        ConsoleHandler ch = new ConsoleHandler();
        ch.setFormatter(new ServerLogFormatter(false));
        ch.setLevel(Level.ALL);
        logger.addHandler(ch);

        FileHandler fh = null;
        try {
            fh = new FileHandler("ChatServer.log", true);
            fh.setFormatter(new ServerLogFormatter(true));
            fh.setLevel(Level.ALL);
            logger.addHandler(fh);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        GuiHandler gh = new GuiHandler();
        gh.setFormatter(new ServerLogFormatter(false));
        gh.setLevel(Level.ALL);
        logger.addHandler(gh);

        LoggingOutputStream los = new LoggingOutputStream(logger, StdOutErrLevel.STDOUT);
        System.setOut(new PrintStream(los, true));

        los = new LoggingOutputStream(logger, StdOutErrLevel.STDERR);
        System.setErr(new PrintStream(los, true));

        didInit = true;
    }

    public static void log(Level level, String text) {
        if (!didInit) {
            Init();
        }

        LogRecord lr = new LogRecord(level, text);
        inferCaller(lr);
        logger.log(lr);
    }

    public static void log(String text) {
        if (!didInit) {
            Init();
        }
        LogRecord lr = new LogRecord(Level.INFO, text);
        inferCaller(lr);
        logger.log(lr);
    }

    public static void logWarning(String text) {
        if (!didInit) {
            Init();
        }
        LogRecord lr = new LogRecord(Level.WARNING, text);
        inferCaller(lr);
        logger.log(lr);
    }

    public static void logError(String text) {
        if (!didInit) {
            Init();
        }
        LogRecord lr = new LogRecord(Level.SEVERE, text);
        inferCaller(lr);
        logger.log(lr);
    }

    public static void log(Connection con, Level level, String text) {
        if (!didInit) {
            Init();
        }

        LogRecord lr = new LogRecord(level, MessageFormat.format("[{0}] {1}", new Object[]{con.getSocketInfo(), text}));
        inferCaller(lr);
        logger.log(lr);
    }

    public static void log(Connection con, String text) {
        if (!didInit) {
            Init();
        }
        LogRecord lr = new LogRecord(Level.INFO, MessageFormat.format("[{0}] {1}", new Object[]{con.getSocketInfo(), text}));
        inferCaller(lr);
        logger.log(lr);
    }

    public static void logWarning(Connection con, String text) {
        if (!didInit) {
            Init();
        }
        LogRecord lr = new LogRecord(Level.WARNING, MessageFormat.format("[{0}] {1}", new Object[]{con.getSocketInfo(), text}));
        inferCaller(lr);
        logger.log(lr);
    }

    public static void logError(Connection con, String text) {
        if (!didInit) {
            Init();
        }
        LogRecord lr = new LogRecord(Level.SEVERE, MessageFormat.format("[{0}] {1}", new Object[]{con.getSocketInfo(), text}));
        inferCaller(lr);
        logger.log(lr);
    }

    private static void inferCaller(LogRecord lr) {

        // true when searching for loggerClassName, false when not.
        boolean isSearchingForLogger = true;

        for (StackTraceElement elem : new Throwable().getStackTrace()) {

            String className = elem.getClassName();
            boolean matches = className.endsWith("ServerLog");

            // Found FormattingLogger in the stack.
            if (matches && isSearchingForLogger) {
                isSearchingForLogger = false;
                continue;
            }

            // Found first call past FormattingLogger.
            if (!matches && !isSearchingForLogger) {
                lr.setSourceClassName(className);
                lr.setSourceMethodName(elem.getMethodName());
                return;
            }

        }
    }
}
